﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

namespace KPIS.GERP.Models.HRM
{
    [DataContract, Table("hrm_ps_time_att_summary")]
    public class PsTimeAttSummary
    {
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), DataMember, Column("tas_seq", Order = 1)]
        public int TasId { get; set; }

        [DataMember, Column("emp_seq", Order = 2), ForeignKey("Employee")]
        public int? EmpId { get; set; }

        [DataMember, Column("cal_for_date", Order = 3)]
        public DateTime? CalForDate { get; set; }

        [DataMember, Column("cal_is_atten", Order = 4)]
        public bool CalIsAtten { get; set; }

        [DataMember, Column("cal_is_late", Order = 5)]
        public bool? CalIsLate { get; set; }

        [DataMember, Column("cal_is_absence_available", Order = 6)]
        public bool? CalIsAbsenceAvailable { get; set; }

        [DataMember, Column("cal_is_getoff_early", Order = 7)]
        public bool? CalIsGetOffEarly { get; set; }

        [DataMember, Column("cal_cant_calculate", Order = 8)]
        public bool CalCantCalculate { get; set; }

        [DataMember, Column("cal_reasons_of_cant_calculate", Order = 9)]
        public string CalReasonsOfCantCalculate { get; set; }

        private void AddCalReasonsOfCantCalculate(string str)
        {
            str = (str ?? string.Empty).Trim();
            CalReasonsOfCantCalculate += string.IsNullOrWhiteSpace(CalReasonsOfCantCalculate) 
                ? str : 
                ", \r\n" + str;
        }

        [DataMember, Column("working_start")]
        public TimeSpan? WorkingStart { get; set; }

        [DataMember, Column("working_end")]
        public TimeSpan? WorkingEnd { get; set; }

        [DataMember, Column("remarks")]
        public string Remarks { get; set; }

        [DataMember, Column("record_status")]
        public string RecordStatus { get; set; }

        [DataMember, Column("created_by")]
        public int? CreatedBy { get; set; }

        [DataMember, Column("created_when")]
        public DateTime? CreatedWhen { get; set; }

        [DataMember, Column("updated_by")]
        public int? UpdatedBy { get; set; }

        [DataMember, Column("updated_when")]
        public DateTime? UpdatedWhen { get; set; }

        [DataMember, Column("cal_lastest_when")]
        public DateTime? CalLastestWhen { get; set; }

        [DataMember, Column("cal_atten_morning")]
        public bool? CalAttenMorning { get; set; }

        [DataMember, Column("cal_atten_morning_late")]
        public bool? CalAttenMorningLate { get; set; }

        [DataMember, Column("cal_getoff_morning")]
        public bool? CalGetOffMorning { get; set; }

        [DataMember, Column("cal_getoff_morning_early")]
        public bool? CalGetOffMorningEarly { get; set; }

        [DataMember, Column("cal_atten_afternoon")]
        public bool? CalAttenAfternoon { get; set; }

        [DataMember, Column("cal_atten_afternoon_late")]
        public bool? CalAttenAfternoonLate { get; set; }

        [DataMember, Column("cal_getoff_afternoon_early")]
        public bool? CalGetOffAfternoonEarly { get; set; }

        [DataMember, Column("cal_start_working_time")]
        public TimeSpan? CalStartWorkingTime { get; set; }

        [DataMember, Column("cal_end_working_time")]
        public TimeSpan? CalEndWorkingTime { get; set; }

        [DataMember, Column("cal_start_working_time_afternoon")]
        public TimeSpan? CalStartWorkingTimeAfternoon { get; set; }

        [DataMember, Column("cal_end_working_time_morning")]
        public TimeSpan? CalEndWorkingTimeMorning { get; set; }


        [DataMember, Column("cal_absence_id"), ForeignKey("Absence")]
        public int? CalAbsenceId { get; set; }

        [DataMember, Column("cal_absence_afternoon_id"), ForeignKey("AbsenceAfternoon")]
        public int? CalAbsenceAfternoonId { get; set; }

        [DataMember, Column("working_seq"), ForeignKey("PsTimeAttendance")]
        public int? WorkingId { get; set; }

        [DataMember]
        public virtual Employee Employee { get; set; }
        [DataMember]
        public virtual PsAbsence Absence { get; set; }
        [DataMember]
        public virtual PsAbsence AbsenceAfternoon { get; set; }
        [DataMember]
        public virtual PsTimeAttendants PsTimeAttendance { get; set; }

        [NotMapped]
        public RuningWorkingHalfDay RuningWorkingMorning { get; set; }

        [NotMapped]
        public RuningWorkingHalfDay RuningWorkingAfternoon { get; set; }

        public PsTimeAttSummary()
        {
            UpdateInitial();
        }

        public PsTimeAttSummary(PsTimeAttendants ta, DateTime dateTime, int empId,
            TimeSpan startWorkingTime, TimeSpan endWorkingTime,
            TimeSpan startWorkingTimeAfternoon, TimeSpan endWorkingTimeMorning)
        {
            UpdateInitial();
            UpdateInfo(ta, dateTime, empId,
                startWorkingTime, endWorkingTime,
                startWorkingTimeAfternoon, endWorkingTimeMorning);
        }

        public void UpdateInfo(PsTimeAttendants ta, DateTime dateTime, int empId,
            TimeSpan startWorkingTime, TimeSpan endWorkingTime,
            TimeSpan startWorkingTimeAfternoon, TimeSpan endWorkingTimeMorning)
        {
            CalStartWorkingTime = startWorkingTime;
            CalEndWorkingTime = endWorkingTime;
            CalStartWorkingTimeAfternoon = startWorkingTimeAfternoon;
            CalEndWorkingTimeMorning = endWorkingTimeMorning;
            if (ta != null && ta.WorkingId != 0)
            {
                WorkingId = ta.WorkingId;
                PsTimeAttendance = ta;
                WorkingStart = ta.WorkingStart;
                WorkingEnd = ta.WorkingEnd;
            }
            EmpId = empId;
            CalForDate = dateTime;
            RuningWorkingMorning = new RuningWorkingHalfDay(dateTime.Date, empId, CalForTime.Morning);
            RuningWorkingAfternoon = new RuningWorkingHalfDay(dateTime.Date, empId, CalForTime.Afternoon);
        }

        private void UpdateInitial()
        {
            RecordStatus = "U";
            CreatedBy = 1;
            CreatedWhen = DateTime.Now;
        }


        public void UpdateAttenStatus(List<PsAbsence> allApprovedAbsences)
        {
            // Invalid
            // WorkingStart WorkingEnd
            // 16:30	    0  #2
            // 8:30	        0  #2
            // 16:30	    20:00
            // 16:31	    20:00
            // 1:00	        8:29
            // 1:00	        8:30
            // 1:00	        8:31 
            CalCantCalculate = true;
            CalReasonsOfCantCalculate = "";
            if (!WorkingId.HasValue)
            {
                CalCantCalculate = false;
                AddCalReasonsOfCantCalculate("[สามารถคำนวนได้ - ไม่มาทำงาน]");
            }
            if ((!WorkingStart.HasValue || WorkingStart == new TimeSpan())
                && WorkingEnd.HasValue)
            {
                AddCalReasonsOfCantCalculate("[ไม่สามารถคำนวนได้] ไม่ระบุเวลาเข้า");
            }
            else if (WorkingStart.HasValue
                     && (!WorkingEnd.HasValue || WorkingEnd == new TimeSpan()))
            {
                AddCalReasonsOfCantCalculate("[ไม่สามารถคำนวนได้] ไม่ระบุเวลาออก");
            }
            else if ((!WorkingStart.HasValue || WorkingStart == new TimeSpan())
                     && (!WorkingEnd.HasValue || WorkingEnd == new TimeSpan()))
            {
                AddCalReasonsOfCantCalculate("[ไม่สามารถคำนวนได้] ไม่ระบุเวลาเข้าและออก");
            }
            else if (WorkingStart > CalEndWorkingTime)
            {
                AddCalReasonsOfCantCalculate("[ไม่สามารถคำนวนได้] มาเริ่มงานหลังเวลาเลิกงาน");
            }
            else if (WorkingEnd < CalStartWorkingTime)
            {
                AddCalReasonsOfCantCalculate("[ไม่สามารถคำนวนได้] เลิกงาน (" + WorkingEnd + ") ก่อนเวลาเริ่มงาน (" + CalStartWorkingTime + ") ");
            }
            else
            {
                CalCantCalculate = false;
                AddCalReasonsOfCantCalculate("[สามารถคำนวนได้ - มาทำงาน]");
            }

            CalLastestWhen = DateTime.Now;
            CalAttenMorning = CalCantCalculate == false && WorkingStart <= CalEndWorkingTimeMorning;
            CalAttenAfternoon = WorkingStart <= CalEndWorkingTime;
            CalAttenMorningLate = CalCantCalculate == false 
                && ((bool) CalAttenMorning) 
                && WorkingStart > CalStartWorkingTime 
                && WorkingStart < CalEndWorkingTimeMorning;
            CalAttenAfternoonLate = ((bool) CalAttenAfternoon) && WorkingStart > CalStartWorkingTimeAfternoon && WorkingStart < CalEndWorkingTime;
            CalGetOffMorningEarly = ((bool) CalAttenMorning) && WorkingEnd < CalEndWorkingTimeMorning;
            CalGetOffMorning = ((bool) CalAttenMorning) && WorkingEnd >= CalEndWorkingTimeMorning && WorkingEnd < CalStartWorkingTimeAfternoon;
            CalGetOffAfternoonEarly = ((bool) CalAttenAfternoon) && WorkingEnd < CalEndWorkingTime;
             
            if (CalAttenMorning == true)
            {
                AddCalReasonsOfCantCalculate("เข้าเช้า");
                if (CalAttenMorningLate == true)
                {
                    AddCalReasonsOfCantCalculate(" (สาย) ");
                }

                if (CalGetOffMorningEarly == true)
                {
                    AddCalReasonsOfCantCalculate(" ออกก่อนพักเที่ยง ");
                }

                if (CalGetOffMorning == true)
                {
                    AddCalReasonsOfCantCalculate(" ออกครึ่งวันช่วงเที่ยง");
                }
            }

            if (CalAttenAfternoon == true)
            {
                AddCalReasonsOfCantCalculate("เข้าบ่าย");
                if (CalAttenAfternoonLate == true)
                {
                    AddCalReasonsOfCantCalculate(" (สาย) ");
                }

                if (CalGetOffAfternoonEarly == true)
                {
                    AddCalReasonsOfCantCalculate(" ออกก่อนเวลาเลิก ");
                }
                else
                {
                    AddCalReasonsOfCantCalculate(" ออกตามเวลาปกติ ");
                }
            }

            // load absence
            var appAbsOfHim = allApprovedAbsences.Where(o => o.EmpId == EmpId);
            foreach (var eachAbsence in appAbsOfHim)
            {
                // if case between, accept
                bool isAcceptMorning = false, isAcceptAfternoon = false;
                if (eachAbsence.StartDate < CalForDate && eachAbsence.EndDate > CalForDate)
                {
                    isAcceptMorning = true;
                    isAcceptAfternoon = true;
                }
                else
                {
                    if (eachAbsence.StartDate == CalForDate && eachAbsence.StartTime == "M")
                    {
                        // วันเริ่มลาตรงกับวันคำนวน และช่วงเวลาเริ่มลาเป็นตอนเช้า
                        isAcceptMorning = true;
                    }
                    else if (eachAbsence.StartDate == CalForDate && eachAbsence.StartTime == "A")
                    {
                        // วันเริ่มลาตรงกับวันคำนวน และช่วงเวลาเริ่มลาเป็นตอนบ่าย
                        isAcceptAfternoon = true;
                    }

                    if (eachAbsence.EndDate == CalForDate && eachAbsence.EndTime == "M")
                    {
                        // วันสุดท้ายการลาตรงกับวันคำนวน และช่วงเวลาสุดท้ายการลาเป็นตอนเช้า
                        isAcceptMorning = true;
                    }
                    else if (eachAbsence.EndDate == CalForDate && eachAbsence.EndTime == "A")
                    {
                        // วันสุดท้ายการลาตรงกับวันคำนวน และช่วงเวลาสุดท้ายการลาเป็นตอนบ่าย
                        isAcceptAfternoon = true;
                    }
                }

                if (isAcceptMorning)
                {
                    CalAbsenceId = eachAbsence.AbsenceId;
                    Absence = eachAbsence;
                }
                else
                {
                    CalAbsenceId = null;
                    Absence = null;
                }

                if (isAcceptAfternoon)
                {
                    CalAbsenceAfternoonId = eachAbsence.AbsenceId;
                    AbsenceAfternoon = eachAbsence;
                }
                else
                {
                    CalAbsenceAfternoonId = null;
                    AbsenceAfternoon = null;
                }

            }

            CalIsAtten = (CalAttenMorning ?? false) || (CalAttenAfternoon ?? false);
            CalIsLate = (CalAttenMorningLate ?? false) || (CalAttenAfternoonLate ?? false);
            CalIsAbsenceAvailable = CalIsAtten
                ? (bool?) null
                : (!(CalAttenMorning ?? false) && CalAbsenceId.HasValue) ||
                  (!(CalAttenAfternoon ?? false) && CalAbsenceAfternoonId.HasValue); 
        }
    }
}